#pragma once

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>
#include <memory>
#include <regex>
 
#include "../Utilities/ChineseExtractor.h"

#include <nlohmann/json.hpp>
#include <cppjieba/Jieba.hpp>
#include <utfcpp/utf8.h>
#include <tinyxml2.h>

using std::ifstream;
using std::istringstream;
using std::vector;
using std::map;
using std::unordered_map;
using std::set;
using std::string;
using std::shared_ptr;

// json类型
using Json = nlohmann::json;


// 类型：候选网页生成
class CandidatePages
{
public:
    // 默认无参构造函数
    CandidatePages() = default;

    // 构造函数：倒排索引库文件、网页偏移库文件、网页库文件、停用词文件
    CandidatePages(const string& invertedIndexFile, const string& pageOffsetFile, 
                   const string& pageLibFile, const string& stopWordFile);
    
    // 设置倒排索引库文件、网页偏移库文件、网页库文件、停用词文件
    void setPageRecommender(const string& invertedIndexFile, const string& pageOffsetFile, 
                            const string& pageLibFile, const string& stopWordFile);

    ~CandidatePages() { close(m_pagesFd); }

    // 根据用户输入内容，分析出相关候选网页并返回 (以json指针格式)
    shared_ptr<Json> getCandidatePages(const string& input);

private:
    // 将输入内容当成一个文档，对其分词（略过停用词）并进行TF-IDF计算，构建 关键词-->权重 的映射
    shared_ptr<unordered_map<string, double>> makeKeywordToWeight(const string& input);

    // 计算基准向量与相关网页之间的余弦相似度
    // 返回值：按照权重降序排列的 网页ID--相似度 二元组序列
    vector<std::pair<int, double>> calculateSimilarity(shared_ptr<unordered_map<string, double>> keywordWeight, 
                                                       shared_ptr<set<int>> relatedPages);

    // 从网页库文件中读取指定文档, 并返回格式化的JSON
    // 参数：文件流的起始位置，文件大小
    Json readPageLib(size_t docStart, size_t docSize);
private:
    unordered_map<string, unordered_map<int, double>> m_invertedIndex;     // 倒排索引库
    unordered_map<int, std::pair<size_t, size_t>> m_pageOffset;            // 网页偏移库
    set<string> m_stopWords;           // 停用词集合
    int m_pagesFd;                      // 网页库文件描述符
    cppjieba::Jieba m_tokenizer;       // 分词器
};


// 工具函数模板：求多个unordered_map的key的交集
// 返回值：一个指向结果集合的shared_ptr
template<typename Key, typename Value>
shared_ptr<set<Key>> unordered_mapIntersection(const vector<unordered_map<Key, Value>*>& vec)
{
    if (vec.empty()) {
        return nullptr;
    }
    auto result = std::make_shared<set<Key>>();
    for (const auto& [key, value] : *vec[0]) {
        bool isIntersection = true;
        for (int i = 1; i < vec.size(); ++i) {
            if ((*vec[i]).find(key) == (*vec[i]).end()) {
                isIntersection = false;
                break;
            }
        }
        if (isIntersection) {
            result->insert(key);
        }
    }
    return result;
}